//
// Created by song on 16-11-24.
//

#ifndef C0COMPILER_OPTIMIZER_H
#define C0COMPILER_OPTIMIZER_H


#include "IR.h"
#include "Function.h"
#include "Graph.h"


class Optimizer {
    SymbolTable* symbolTable;
    vector<Function*> funList;
    map<TmpVar*, SymbolTable::VarRecord*> varMap;
    Graph graph;
    map<TmpVar*, map<IR*, int>*> colors;

public:
    IRList* irList;
    Optimizer(IRList *irList, SymbolTable *pTable) : irList(irList),symbolTable(pTable){};

private:
    void buildTmpVar2SymbolMap(){
        for(int i=0; i<symbolTable->varTable.size(); i++){
            SymbolTable::VarRecord* v = symbolTable->varTable[i];
            varMap[v->ref] = v;
        }
    }

    void cutToFunction(){
        Function* function;
        vector<IR*>::const_iterator iter;
        IR* fBegin=NULL, *fEnd=NULL;
        for(iter=irList->begin(); iter!= irList->end(); iter++){
            IR* ir = *iter;
            if(ir->op==FUNBEGIN){
                fBegin=ir;
            }
            if(ir->op==FUNEND){
                fEnd=ir;
                if(fBegin!=NULL){
                    function = new Function(irList, symbolTable, varMap);
                    funList.push_back(function);
                    function->cutToBlock(fBegin, fEnd);
//                    cout << fBegin->toString() << endl;
//                    cout << fEnd->toString() << endl;
                    fBegin=NULL;
                }else{
                    Error::internal(Error::Should_Not_Happen);
                }
            }
        }
    }

public:
    int getColor(TmpVar* var, IR* ir){
        if(colors.count(var)>0){
            map<IR*, int> &irMap = *(colors[var]);
            if(irMap.count(ir)>0){
                return irMap[ir];
            }
        }
        Error::nextErrorDetail << "var color not set (" << var->name() <<", "<<ir->id << ')';
        Error::internal(Error::Should_Not_Happen);
    }

    void optimize(){
        buildTmpVar2SymbolMap();

        cutToFunction();
        DefUseChain::mergeChainToNode();
        if(Config::printDefUseChains) DefUseChain::printAll();
        if(Config::printMergedDFChain) DefUseChain::Node::printAll();

        cout << "#++++++++++++ colors +++++++++++++" << endl;
        graph.assignRegisters(3);
        vector<DefUseChain::Node*> & nodes = DefUseChain::Node::list;
        for(int i=0; i<nodes.size(); i++){
            int color = graph.getColor(nodes[i]);
            if(colors.count(nodes[i]->var)==0){
                colors[nodes[i]->var] = new map<IR*, int>();
            }
            map<IR*, int> &irMap = *(colors[nodes[i]->var]);
            for(set<IR*>::const_iterator j=nodes[i]->def.begin() ; j!=nodes[i]->def.end(); j++){
                IR* ir = *j;
                irMap[ir] = color;
            }
        }

        if(Config::printBasicBlocks){
            for(int i=0; i<funList.size(); i++){
                cout << funList[i]->toString() << endl;
            }
        }
    }

};



#endif //C0COMPILER_OPTIMIZER_H
